package com.caj.id;

import org.springframework.stereotype.Component;


public class SnowFlake {
    //12位序列号：从第0号到第4095号
    private long sequenceId = 0L;
    //机器ID号:从第0位到第31位
    private long workId;
    //数据中心ID号：从第0位到第31位
    private long dataId;

    //机器ID号占用位数
    private long workIdBits = 5L;
    //最大的机器ID号
    private long maxWorkId = ~(-1L << workIdBits);
    //数据中心ID号占用位数
    private long dataIdBits = 5L;
    //最大的数据中心ID号
    private long maxDataId = ~(-1L << dataIdBits);
    //序列号占用的位数
    private long sequenceIdBits = 12L;
    //序列号的掩码
    private long sequenceMask = ~(-1L << sequenceIdBits);

    //最终生成的机器ID：需左移sequenceIdBits位
    private long workIdShift = sequenceIdBits;
    //最终生成的数据中心ID：需左移sequenceIdBits + workIdBits位
    private long dataIdShift = sequenceIdBits + workIdBits;
    //最终生成的时间戳ID：需左移sequenceIdBits + workIdBits + dataIdBits位
    private long timeStampIdShift = sequenceIdBits + workIdBits + dataIdBits;

    //基准时间 2025-08-05 21:18:33
    private long timeEpoch = 1754399913000L;

    //记录上一次的时间戳
    private long lastTimeStamp = -1L;

    public SnowFlake(long dataId, long workId){
        if(dataId > maxDataId || dataId < 0L){
            throw new IllegalArgumentException(String.format("dataId can not greater than %d or less than 0", maxDataId));
        }
        if(workId > maxWorkId || workId < 0L){
            throw new IllegalArgumentException(String.format("workId can not greater than %d or less than 0", maxWorkId));
        }
        this.dataId = dataId;
        this.workId = workId;
    }

    public synchronized long nextId(){
        long timeStamp = System.currentTimeMillis();
        //防止出现时间回拨：当服务器未连上网，本地机器由于温度等原因会出现时间戳不准确问题
        if(timeStamp < lastTimeStamp){
            throw new RuntimeException(String.format("Clock moved backwords %d ", lastTimeStamp - timeStamp));
        }
        if(timeStamp == lastTimeStamp){
            sequenceId = (sequenceId + 1) & sequenceMask;
            //说明这个时间戳下，已经生成了第4097个ID，当前的时间戳不够用了，此时等待下一个时间戳
            if(sequenceId == 0L){
                //自旋等待
                while(timeStamp <= lastTimeStamp){
                    timeStamp = System.currentTimeMillis();
                }
            }
        }else{
           sequenceId = 0L;
        }
        lastTimeStamp = timeStamp;
        // 移位并通过或运算拼到一起组成64位的ID
        return (timeStamp - timeEpoch) << timeStampIdShift |
                dataId << dataIdShift |
                workId << workIdShift |
                sequenceId;
    }


}
